package com.ruihu.admin.module.business.tasknode.manager;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.ruihu.admin.common.anno.MethodLog;
import com.ruihu.admin.common.anno.OperateLog;
import com.ruihu.admin.common.constant.ResponseCodeConst;
import com.ruihu.admin.common.domain.ResponseDTO;
import com.ruihu.admin.constant.CommonConst;
import com.ruihu.admin.module.business.task.constant.TaskResponseCodeConst;
import com.ruihu.admin.module.business.tasknode.dao.TaskNodeFileDao;
import com.ruihu.admin.module.business.tasknode.domain.dto.NodeInstProcessRelationAddDTO;
import com.ruihu.admin.module.business.tasknode.domain.dto.NodeInstProcessRelationUpdateDTO;
import com.ruihu.admin.module.business.tasknode.domain.dto.TaskNodeFileDeleteDTO;
import com.ruihu.admin.module.business.tasknode.domain.entity.SubTaskNodeInstEntity;
import com.ruihu.admin.module.business.tasknode.domain.entity.TaskNodeFileEntity;
import com.ruihu.admin.module.support.file.constant.FileSourceEnum;
import com.ruihu.admin.module.support.file.dao.FileDao;
import com.ruihu.admin.module.support.file.domain.dto.FileDTO;
import com.ruihu.admin.module.support.file.domain.dto.FileUpdateDTO;
import com.ruihu.admin.module.support.file.domain.entity.FileEntity;
import com.ruihu.admin.module.support.file.service.FileServiceLocal;
import com.ruihu.admin.module.support.file.service.IFileService;
import com.ruihu.admin.util.RequestTokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.jetbrains.annotations.NotNull;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.util.*;

@Service
@Slf4j
public class TaskNodeFileManager {

    @Autowired
    private TaskNodeFileDao taskNodeFileDao;

    @Autowired
    private FileDao fileDao;

    @Autowired
    private SqlSessionTemplate sqlSessionTemplate;

    @Value("${file-upload-service.path}")
    private String fileBasePath;

    @MethodLog
    @Transactional(rollbackFor = Exception.class)
    public ResponseDTO<String> deleteTaskNodeFile(TaskNodeFileDeleteDTO deleteDTO) {
        if (Objects.nonNull(deleteDTO.getId())) {
            TaskNodeFileEntity taskNodeFileEntity = this.taskNodeFileDao.selectById(deleteDTO.getId());

            if (null == taskNodeFileEntity) {
                return ResponseDTO.wrap(TaskResponseCodeConst.TASK_NODE_FILE_NOT_FOUND);
            }

            if (Objects.nonNull(taskNodeFileEntity.getFileId())) {
                FileEntity fileEntity = this.fileDao.selectById(taskNodeFileEntity.getFileId());
                this.fileDao.deleteById(taskNodeFileEntity.getFileId());
                // 删除磁盘附件
                File file = new File(this.fileBasePath + File.separator + fileEntity.getFilePath());
                if (file.exists()) {
                    FileUtil.del(file);
                    log.info("Delete file {} ", file.getAbsolutePath());
                }
                String fileName = file.getName().replace(CommonConst.THUMBNAIL_PREFIX, StrUtil.EMPTY);
                file = new File(FileUtil.getParent(file, 1) + File.separator + fileName);
                if (file.exists()) {
                    FileUtil.del(file);
                    log.info("Delete file {} ", file.getAbsolutePath());
                }
            }
            // 删除文件关联
            this.taskNodeFileDao.deleteById(taskNodeFileEntity.getId());
        } else if (StrUtil.isNotEmpty(deleteDTO.getFilePath())) {
            FileDTO fileDTO = this.fileDao.queryByFilePath(deleteDTO.getFilePath());
            if (Objects.nonNull(fileDTO)) {
                this.fileDao.deleteById(fileDTO.getId());
            }
            // 删除磁盘附件
            File file = new File(this.fileBasePath + File.separator  + deleteDTO.getFilePath());
            if (file.exists()) {
                FileUtil.del(file);
                log.info("Delete file {} ", file.getAbsolutePath());
            }
            String fileName = file.getName().replace(CommonConst.THUMBNAIL_PREFIX, StrUtil.EMPTY);
            file = new File(FileUtil.getParent(file, 1) + File.separator + fileName);
            if (file.exists()) {
                FileUtil.del(file);
                log.info("Delete file {} ", file.getAbsolutePath());
            }
        }

        return ResponseDTO.succ();
    }

    /**
     * 新增附件
     * @param subTaskNodeInstEntity
     * @param nodeInstRelationList
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public ResponseDTO<String> addFileList(SubTaskNodeInstEntity subTaskNodeInstEntity, List<NodeInstProcessRelationUpdateDTO> nodeInstRelationList) {
        Assert.notNull(subTaskNodeInstEntity);
        if (CollectionUtil.isEmpty(nodeInstRelationList))
            return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM);

        SqlSession sqlSession = this.sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false);
        String insertFileSqlId = FileDao.class.getName() + ".insert";
        Map<String, List<FileEntity>> fileEntityMap = new HashMap<>();
        nodeInstRelationList.forEach(e -> {
            String nodeInstProcessRelationId = String.valueOf(e.getId());
            fileEntityMap.put(nodeInstProcessRelationId, new ArrayList<>());
            List<FileUpdateDTO> fileList = e.getFileList();
            if (CollectionUtil.isNotEmpty(fileList)) {
                fileList.forEach(file -> {
                    if (Objects.isNull(file.getId())) {
                        FileEntity fileEntity = FileEntity.convertToFileEntity(file);
                        if (StrUtil.isEmpty(file.getFileName())) {
                            fileEntity.setFileName(file.getFileOrigName());
                        }
                        fileEntity.setFileName(fileEntity.getFileName());
                        fileEntity.setFileType(FileUtil.extName(fileEntity.getFileName()));
                        fileEntity.setFileOrigName(file.getFileOrigName());
                        fileEntity.setCreaterUser(RequestTokenUtil.getRequestUser().getRequestUserId());
                        fileEntity.setCreateTime(new Date());
                        sqlSession.insert(insertFileSqlId, fileEntity);
                        fileEntityMap.get(nodeInstProcessRelationId).add(fileEntity);
                    }
                });
            }
        });
        sqlSession.commit();

        // 保存新的文件关联到任务节点实例表
        String sqlId = TaskNodeFileDao.class.getName() + ".insert";
        String finalSqlId = sqlId;
        fileEntityMap.forEach((processRelationId, fileEntityList) -> {
            fileEntityList.forEach(fileEntity -> {
                TaskNodeFileEntity taskNodeFileEntity = getTaskNodeFileEntity(subTaskNodeInstEntity, fileEntity, Long.valueOf(processRelationId));
                sqlSession.insert(finalSqlId, taskNodeFileEntity);
            });
        });
        sqlSession.commit();

        return ResponseDTO.succ();
    }

    @NotNull
    private TaskNodeFileEntity getTaskNodeFileEntity(SubTaskNodeInstEntity subTaskNodeInstEntity, FileEntity fileEntity, Long processRelationId) {
        TaskNodeFileEntity taskNodeFileEntity = new TaskNodeFileEntity();
        taskNodeFileEntity.setSubTaskId(subTaskNodeInstEntity.getSubTaskId());
        taskNodeFileEntity.setTaskNodeInstId(subTaskNodeInstEntity.getTaskNodeInstId());
        taskNodeFileEntity.setSubTaskNodeInstId(subTaskNodeInstEntity.getId());
        taskNodeFileEntity.setProcessRelationId(processRelationId);
        taskNodeFileEntity.setFileId(fileEntity.getId());
        taskNodeFileEntity.setRevision(CommonConst.DEFAULT_OPTI_LOCK_REVISION);
        taskNodeFileEntity.setCreateBy(RequestTokenUtil.getRequestUser().getRequestUserId());
        taskNodeFileEntity.setCreateTime(new Date());
        return taskNodeFileEntity;
    }
}
